package ua.kpi.ipsa.expert.api.client;

import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.rmi.RemoteException;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import javax.swing.GroupLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.JTree;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;

import ua.kpi.ipsa.expert.api.net.CodePortion;
import ua.kpi.ipsa.expert.api.net.ConsoleException;
import ua.kpi.ipsa.expert.api.net.SourceFile;

public class BrowseSource {
	public TreeNode createNode() {
		Collections.sort(portion.sourceList, new Comparator<SourceFile>() {

			@Override
			public int compare(SourceFile f1, SourceFile f2) {
				int i = 0;
				while (i < f1.path.length && i < f2.path.length
						&& f1.path[i] == f2.path[i])
					++i;
				if (f1.path.length > i + 1 && f2.path.length <= i + 1)
					return -1;
				if (f1.path.length <= i +1 && f2.path.length > i + 1)
					return 1;
				if (f1.path.length <= i + 1 && f2.path.length <= i + 1)
					return 0;
				return f1.path[i].compareTo(f2.path[i]);
			}
		});
		return createNode("Portion", portion.sourceList, 0,
				portion.sourceList.size(), 0);
	}

	private DefaultMutableTreeNode createNode(String name,
			List<SourceFile> list, int begin, int end, int level) {
		DefaultMutableTreeNode root = new DefaultMutableTreeNode(name);
		int i = begin;
		while (i < end && list.get(i).path.length > level + 1) {
			int j = i;
			while (i < end && list.get(i).path.length > level + 1
					&& list.get(i).path[level] == list.get(j).path[level])
				++i;
			root.add(createNode(list.get(j).path[level], list, j, i, level + 1));
		}
		for (; i < end; ++i) {
			root.add(new DefaultMutableTreeNode(list.get(i)) {
				@Override
				public String toString() {
					String[] path = ((SourceFile) userObject).path;
					return path[path.length - 1];
				}
			});
		}
		return root;
	}

	private ClientFrameManager m;
	private JFrame parent;

	private JFrame f;
	private JTree tree;
	private JScrollPane treeScroll;
	private JTextArea text;
	private JScrollPane textScroll;
	private JSplitPane split;
	private JButton backBtn;
	private CodePortion portion;

	public BrowseSource(ClientFrameManager m, JFrame parent, int codePortionID) {
		this.m = m;
		this.parent = parent;
		try {
			portion = m.getConsole().getCodePortion(codePortionID);
		} catch (RemoteException | ConsoleException e) {
			error(e);
			return;
		}
		f = m.createFrame();
		doLayout();
		f.setVisible(true);
	}

	private void doLayout() {
		f.setTitle("Source code");
		f.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
		f.addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				exit();
			}
		});
		tree = new JTree(createNode());
		tree.setPreferredSize(new Dimension(200, 300));
		treeScroll = new JScrollPane(tree);
		text = new JTextArea(30, 20);
		text.setEditable(false);
		textScroll = new JScrollPane(text);
		split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, treeScroll,
				textScroll);
		backBtn = new JButton("Back");

		tree.addTreeSelectionListener(new TreeSelectionListener() {

			@Override
			public void valueChanged(TreeSelectionEvent e) {
				setText();
			}

		});

		backBtn.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				exit();
			}
		});

		GroupLayout g = new GroupLayout(f.getContentPane());
		f.setLayout(g);
		g.setAutoCreateContainerGaps(true);
		g.setAutoCreateGaps(true);
		g.setHorizontalGroup(g.createParallelGroup().addComponent(split)
				.addComponent(backBtn));
		g.setVerticalGroup(g.createSequentialGroup().addComponent(split)
				.addComponent(backBtn));
		f.pack();
		f.setLocationRelativeTo(null);
	}

	private void setText() {
		String code = "";
		TreePath path = tree.getSelectionPath();
		if (path != null) {
			Object o = ((DefaultMutableTreeNode) path.getLastPathComponent())
					.getUserObject();
			if (o instanceof SourceFile) {
				code = ((SourceFile) o).body;
			}
		}
		text.setText(code);
	}

	private void exit() {
		m.disposeFrame(f);
		parent.setVisible(true);
	}

	private void error(Throwable e) {
		JOptionPane.showMessageDialog(null, "Connection error", "Error",
				JOptionPane.ERROR_MESSAGE);
		e.printStackTrace();
		m.ceaseOperations();
	}
}
